"""
API数据模型定义
使用Pydantic进行数据验证和序列化
"""

from pydantic import BaseModel, Field, validator
from typing import List, Tuple, Optional, Dict, Any
from enum import Enum


class NodeModel(BaseModel):
    """节点数据模型"""
    id: str = Field(..., description="节点唯一标识符", min_length=1)
    longitude: float = Field(..., description="经度", ge=-180, le=180)
    latitude: float = Field(..., description="纬度", ge=-90, le=90)
    
    class Config:
        json_schema_extra = {
            "example": {
                "id": "A",
                "longitude": 117.0016534,
                "latitude": 38.85764652
            }
        }


class EdgeModel(BaseModel):
    """边数据模型"""
    from_node: str = Field(..., description="起始节点ID", min_length=1)
    to_node: str = Field(..., description="目标节点ID", min_length=1)
    
    @validator('to_node')
    def nodes_must_be_different(cls, v, values):
        if 'from_node' in values and v == values['from_node']:
            raise ValueError('起始节点和目标节点不能相同')
        return v
    
    class Config:
        json_schema_extra = {
            "example": {
                "from_node": "A",
                "to_node": "B"
            }
        }


class NoFlyZoneModel(BaseModel):
    """禁飞区数据模型"""
    name: Optional[str] = Field(None, description="禁飞区名称")
    coordinates: List[Tuple[float, float]] = Field(
        ..., 
        description="禁飞区边界坐标点列表",
        min_items=3
    )
    
    @validator('coordinates')
    def validate_coordinates(cls, v):
        for lon, lat in v:
            if not (-180 <= lon <= 180):
                raise ValueError(f'经度 {lon} 超出有效范围 [-180, 180]')
            if not (-90 <= lat <= 90):
                raise ValueError(f'纬度 {lat} 超出有效范围 [-90, 90]')
        return v
    
    class Config:
        json_schema_extra = {
            "example": {
                "name": "禁飞区1",
                "coordinates": [
                    [117.0220, 38.9745],
                    [117.0265, 38.9745],
                    [117.0265, 38.9785],
                    [117.0220, 38.9785]
                ]
            }
        }


class PathPlanningRequest(BaseModel):
    """路径规划请求模型"""
    nodes: List[NodeModel] = Field(..., description="节点列表", min_items=2)
    edges: List[EdgeModel] = Field(..., description="边列表", min_items=1)
    start_node: str = Field(..., description="起始节点ID", min_length=1)
    end_node: str = Field(..., description="结束节点ID", min_length=1)
    no_fly_zones: Optional[List[NoFlyZoneModel]] = Field(
        default=[], 
        description="禁飞区列表"
    )
    max_match_distance: float = Field(
        default=700, 
        description="最大匹配距离（米）",
        gt=0
    )
    
    @validator('start_node')
    def validate_start_node_exists(cls, v, values):
        if 'nodes' in values:
            node_ids = [node.id for node in values['nodes']]
            if v not in node_ids:
                raise ValueError(f'起始节点 {v} 不在节点列表中')
        return v
    
    @validator('end_node')
    def validate_end_node_exists(cls, v, values):
        if 'nodes' in values:
            node_ids = [node.id for node in values['nodes']]
            if v not in node_ids:
                raise ValueError(f'结束节点 {v} 不在节点列表中')
        if 'start_node' in values and v == values['start_node']:
            raise ValueError('起始节点和结束节点不能相同')
        return v
    
    @validator('edges')
    def validate_edges_reference_existing_nodes(cls, v, values):
        if 'nodes' in values:
            node_ids = set(node.id for node in values['nodes'])
            for edge in v:
                if edge.from_node not in node_ids:
                    raise ValueError(f'边引用的节点 {edge.from_node} 不存在')
                if edge.to_node not in node_ids:
                    raise ValueError(f'边引用的节点 {edge.to_node} 不存在')
        return v
    
    class Config:
        json_schema_extra = {
            "example": {
                "nodes": [
                    {"id": "A", "longitude": 117.0016534, "latitude": 38.85764652},
                    {"id": "B", "longitude": 117.010124, "latitude": 38.85778917},
                    {"id": "C", "longitude": 117.0199953, "latitude": 38.85810291}
                ],
                "edges": [
                    {"from_node": "A", "to_node": "B"},
                    {"from_node": "B", "to_node": "C"}
                ],
                "start_node": "A",
                "end_node": "C",
                "no_fly_zones": [
                    {
                        "name": "禁飞区1",
                        "coordinates": [
                            [117.0220, 38.9745],
                            [117.0265, 38.9745],
                            [117.0265, 38.9785],
                            [117.0220, 38.9785]
                        ]
                    }
                ],
                "max_match_distance": 700
            }
        }


class PathSegment(BaseModel):
    """路径段模型"""
    segment: int = Field(..., description="段号")
    from_node: str = Field(..., description="起始节点")
    to_node: str = Field(..., description="目标节点")
    distance: float = Field(..., description="距离（米）")
    edge_type: str = Field(..., description="边类型：原始边/补充边/绕飞边")
    from_coord: Tuple[float, float] = Field(..., description="起始坐标 [经度, 纬度]")
    to_coord: Tuple[float, float] = Field(..., description="目标坐标 [经度, 纬度]")


class PathPlanningResponse(BaseModel):
    """路径规划响应模型"""
    success: bool = Field(..., description="规划是否成功")
    message: str = Field(..., description="响应消息")
    path: List[str] = Field(default=[], description="路径节点序列")
    total_distance: float = Field(default=0, description="总距离（米）")
    path_details: List[PathSegment] = Field(default=[], description="路径详细信息")
    processing_time: Optional[float] = Field(None, description="处理时间（秒）")
    
    class Config:
        json_schema_extra = {
            "example": {
                "success": True,
                "message": "成功规划路径，总长度: 1250.45米",
                "path": ["A", "B", "C"],
                "total_distance": 1250.45,
                "path_details": [
                    {
                        "segment": 1,
                        "from_node": "A",
                        "to_node": "B",
                        "distance": 625.23,
                        "edge_type": "原始边",
                        "from_coord": [117.0016534, 38.85764652],
                        "to_coord": [117.010124, 38.85778917]
                    }
                ],
                "processing_time": 0.125
            }
        }


class ErrorResponse(BaseModel):
    """错误响应模型"""
    success: bool = Field(False, description="操作是否成功")
    error: str = Field(..., description="错误类型")
    message: str = Field(..., description="错误消息")
    detail: Optional[Dict[str, Any]] = Field(None, description="错误详情")
    
    class Config:
        json_schema_extra = {
            "example": {
                "success": False,
                "error": "ValidationError",
                "message": "输入数据验证失败",
                "detail": {
                    "field": "start_node",
                    "value": "X",
                    "issue": "起始节点 X 不在节点列表中"
                }
            }
        }


class HealthResponse(BaseModel):
    """健康检查响应模型"""
    status: str = Field(..., description="服务状态")
    version: str = Field(..., description="版本号")
    timestamp: str = Field(..., description="时间戳")
    
    class Config:
        json_schema_extra = {
            "example": {
                "status": "healthy",
                "version": "1.0.0",
                "timestamp": "2024-01-01T12:00:00Z"
            }
        }


# 状态枚举
class ServiceStatus(str, Enum):
    HEALTHY = "healthy"
    UNHEALTHY = "unhealthy"
    MAINTENANCE = "maintenance"


# 便捷创建函数
def create_rectangular_no_fly_zone_model(
    name: str,
    center_lon: float, 
    center_lat: float,
    width: float, 
    height: float
) -> NoFlyZoneModel:
    """创建矩形禁飞区模型"""
    half_width = width / 2
    half_height = height / 2
    
    coordinates = [
        (center_lon - half_width, center_lat - half_height),
        (center_lon + half_width, center_lat - half_height),
        (center_lon + half_width, center_lat + half_height),
        (center_lon - half_width, center_lat + half_height)
    ]
    
    return NoFlyZoneModel(name=name, coordinates=coordinates)
